/*
 * Copyright (c) 2024 Shenzhen Kaihong Digital Industry Development Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "sle_connect_parcel.h"
#include "sle_hilog.h"

namespace OHOS {
namespace NearLink {
namespace SleStandard {
SleConnectionParam::SleConnectionParam(const SleConnectParam &param)
{
    intervalMin_ = param.intervalMin;
    intervalMax_ = param.intervalMax;
    latency_ = param.latency;
    supervisionTimeout_ = param.supervisionTimeout;
}

bool SleConnectionParam::Marshalling(Parcel &parcel) const
{
    if(!parcel.WriteUint16(intervalMin_)) {
        return false;
    }
    if(!parcel.WriteUint16(intervalMax_)) {
        return false;
    }
    if(!parcel.WriteUint16(latency_)) {
        return false;
    }
    if(!parcel.WriteUint16(supervisionTimeout_)) {
        return false;
    }
    return true;
}

SleConnectionParam *SleConnectionParam::Unmarshalling(Parcel &parcel)
{
    SleConnectionParam *param = new SleConnectionParam();
    if (param != nullptr && !param->ReadFromParcel(parcel)) {
        delete param;
        param = nullptr;
    }
    return param;
}

bool SleConnectionParam::ReadFromParcel(Parcel &parcel)
{
    if (!parcel.ReadUint16(intervalMin_)) {
        return false;
    }
    if (!parcel.ReadUint16(intervalMax_)) {
        return false;
    }
    if (!parcel.ReadUint16(latency_)) {
        return false;
    }
    if (!parcel.ReadUint16(supervisionTimeout_)) {
        return false;
    }
    return true;
}

void SleConnectionParam::ConvertToSleConnectParam(SleConnectParam &param) const
{
    param.intervalMin = intervalMin_;
    param.intervalMax = intervalMax_;
    param.latency = latency_;
    param.supervisionTimeout = supervisionTimeout_;
}

SleErrorCode SleConnectionParam::CheckConnectParam(const SleConnectParam &param)
{
    SLE_ASSERT_AND_RETURN_RET_LOG(param.intervalMin >= 0x000A && param.intervalMin <= 0x3E80,
        SLE_ERR_INVALID_PARAM, "param connect interval min error!");
    SLE_ASSERT_AND_RETURN_RET_LOG(param.intervalMax >= 0x000A && param.intervalMax <= 0x3E80,
        SLE_ERR_INVALID_PARAM, "param connect interval max error!");
    SLE_ASSERT_AND_RETURN_RET_LOG(param.intervalMin <= param.intervalMax,
        SLE_ERR_INVALID_PARAM, "param connect interval error!");
    SLE_ASSERT_AND_RETURN_RET_LOG(param.latency <= 0x01F3,
        SLE_ERR_INVALID_PARAM, "param connect latency error!");
    SLE_ASSERT_AND_RETURN_RET_LOG(param.supervisionTimeout >= 0x000A && param.supervisionTimeout <= 0x0C80,
        SLE_ERR_INVALID_PARAM, "param connect supervision timeout error!");
    SLE_ASSERT_AND_RETURN_RET_LOG(param.latency < param.supervisionTimeout,
        SLE_ERR_INVALID_PARAM, "param connect latency than supervisionTimeout error!");
    return SLE_NO_ERROR;
}

SleAuthenticationInfo::SleAuthenticationInfo(const SleAuthInfo &info)
{
    for (size_t i = 0; i < SLE_LINK_KEY_LEN; i++) {
        linkKey_[i] = info.linkKey[i];
    }
    cryptoAlgoType_ = info.cryptoAlgo;
    keyDerivAlgoType_ = info.keyDerivAlgo;
    integrChkInd_ = info.integrChkInd;

}

bool SleAuthenticationInfo::Marshalling(Parcel &parcel) const
{
    for (size_t i = 0; i < SLE_LINK_KEY_LEN; i++) {
        if (!parcel.WriteUint8(linkKey_[i])) {
            return false;
        }
    }
    if (!parcel.WriteUint8(cryptoAlgoType_)) {
        return false;
    }
    if (!parcel.WriteUint8(keyDerivAlgoType_)) {
        return false;
    }
    if (!parcel.WriteUint8(integrChkInd_)) {
        return false;
    }
    return true;
}

SleAuthenticationInfo *SleAuthenticationInfo::Unmarshalling(Parcel &parcel)
{
    SleAuthenticationInfo *info = new SleAuthenticationInfo();
    if (info != nullptr && !info->ReadFromParcel(parcel)) {
        delete info;
        info = nullptr;
    }
    return info;
}

bool SleAuthenticationInfo::ReadFromParcel(Parcel &parcel)
{
    for (int i = 0; i < SLE_LINK_KEY_LEN; i++) {
        if (!parcel.ReadUint8(linkKey_[i])) {
            return false;
        }
    }
    if (!parcel.ReadUint8(cryptoAlgoType_)) {
        return false;
    }
    if (!parcel.ReadUint8(keyDerivAlgoType_)) {
        return false;
    }
    if (!parcel.ReadUint8(integrChkInd_)) {
        return false;
    }
    return true;
}

void SleAuthenticationInfo::ConvertToSleAuthInfo(SleAuthInfo &info) const
{
    for (size_t i = 0; i < SLE_LINK_KEY_LEN; i++) {
        info.linkKey[i] = linkKey_[i];
    }
    info.cryptoAlgo = (SleCryptoAlgo)cryptoAlgoType_;
    info.keyDerivAlgo = (SleKeyDerivAlgo)keyDerivAlgoType_;
    info.integrChkInd = (SleIntegrChkInd)integrChkInd_;
}

SleConnectDevice::SleConnectDevice(const SleConnectDev &device)
{
    connectId_ = device.connId;
    SleAddress addr(device.addr);
    address_ = addr;
}

bool SleConnectDevice::Marshalling(Parcel &parcel) const
{
    if(!parcel.WriteUint16(connectId_)) {
        return false;
    }
    if (!parcel.WriteParcelable(&address_)) {
        return false;
    }
    return true;
}

SleConnectDevice *SleConnectDevice::Unmarshalling(Parcel &parcel)
{
    SleConnectDevice *device = new SleConnectDevice();
    if (device != nullptr && !device->ReadFromParcel(parcel)) {
        delete device;
        device = nullptr;
    }
    return device;
}

bool SleConnectDevice::ReadFromParcel(Parcel &parcel)
{
    if (!parcel.ReadUint16(connectId_)) {
        return false;
    }
    std::shared_ptr<SleAddress> address(parcel.ReadParcelable<SleAddress>());
    if (!address) {
        return false;
    }
    address_ = *address;
    return true;
}

void SleConnectDevice::ConvertToSleConnectDev(SleConnectDev &device) const
{
    device.connId = connectId_;
    device.addr = address_.ConvertToSleDeviceAddress();
}
} // SleStandard
} // NearLink
} // OHOS